<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"
    />
    <title>Android中JSBridge的原理与实现 | zzqhost</title>
    <meta name="description" content="天行健，君子以自强不息；地势坤，君子以厚德载物" />
    <meta property="og:type" content="website" />
    <meta property="og:title" content="Android中JSBridge的原理与实现 | zzqhost" />
    <meta property="og:site_name" content="Android中JSBridge的原理与实现 | zzqhost" />
    <meta property="og:locale" content="zh-CN" />
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="Android中JSBridge的原理与实现 | zzqhost" />
    <link rel="shortcut icon" href="/favicon.ico">
    
    <link rel="preload" href="/assets/css/0.styles.948dbb0a.css" as="style"><link rel="preload" href="/assets/js/app.3e01f5cb.js" as="script"><link rel="preload" href="/assets/js/1.21aaee9f.js" as="script"><link rel="preload" href="/assets/js/14.98a4de9c.js" as="script"><link rel="preload" href="/assets/js/5.352c1a43.js" as="script"><link rel="preload" href="/assets/js/7.4a8a313c.js" as="script"><link rel="preload" href="/assets/js/9.5ce2172b.js" as="script"><link rel="preload" href="/assets/js/6.8b8fad13.js" as="script"><link rel="preload" href="/assets/js/20.95040517.js" as="script"><link rel="preload" href="/assets/js/13.186562af.js" as="script"><link rel="preload" href="/assets/js/15.740f4afc.js" as="script"><link rel="prefetch" href="/assets/js/10.e3f309c4.js"><link rel="prefetch" href="/assets/js/11.7bef5ef0.js"><link rel="prefetch" href="/assets/js/12.cf546b2f.js"><link rel="prefetch" href="/assets/js/16.c0f3e779.js"><link rel="prefetch" href="/assets/js/17.ee3f21b3.js"><link rel="prefetch" href="/assets/js/18.2c35035c.js"><link rel="prefetch" href="/assets/js/19.e4881cfc.js"><link rel="prefetch" href="/assets/js/21.cdbb212e.js"><link rel="prefetch" href="/assets/js/22.7d278bc3.js"><link rel="prefetch" href="/assets/js/23.1e2b813e.js"><link rel="prefetch" href="/assets/js/24.6cc55189.js"><link rel="prefetch" href="/assets/js/25.ea35ed40.js"><link rel="prefetch" href="/assets/js/26.2b97bfde.js"><link rel="prefetch" href="/assets/js/27.d323aa74.js"><link rel="prefetch" href="/assets/js/28.30416d07.js"><link rel="prefetch" href="/assets/js/29.02b97357.js"><link rel="prefetch" href="/assets/js/30.95aedede.js"><link rel="prefetch" href="/assets/js/31.79b824fd.js"><link rel="prefetch" href="/assets/js/32.d0cd6341.js"><link rel="prefetch" href="/assets/js/33.14c3c5b9.js"><link rel="prefetch" href="/assets/js/34.ac56f38e.js"><link rel="prefetch" href="/assets/js/35.54820345.js"><link rel="prefetch" href="/assets/js/36.37013d97.js"><link rel="prefetch" href="/assets/js/37.38353206.js"><link rel="prefetch" href="/assets/js/38.36296a20.js"><link rel="prefetch" href="/assets/js/39.37df68d6.js"><link rel="prefetch" href="/assets/js/4.54d65165.js"><link rel="prefetch" href="/assets/js/40.ffbd7a88.js"><link rel="prefetch" href="/assets/js/41.5db561d2.js"><link rel="prefetch" href="/assets/js/42.d876627b.js"><link rel="prefetch" href="/assets/js/43.e5008459.js"><link rel="prefetch" href="/assets/js/44.a24dc4a2.js"><link rel="prefetch" href="/assets/js/45.f696c4e1.js"><link rel="prefetch" href="/assets/js/8.8c0e5954.js"><link rel="prefetch" href="/assets/js/vendors~search.c4563fd1.js">
    <link rel="stylesheet" href="/assets/css/0.styles.948dbb0a.css">
  </head>
  <body>
    <div id="loader-wrapper" style="display: none;opacity:0">
      <div id="loader"></div>
      <div class="loader-section section-left"></div>
      <div class="loader-section section-right"></div>
    </div>
    <div id="app" data-server-rendered="true"><div style="height:100%;" data-v-80d5f2bc><section class="el-container main-container" data-v-80d5f2bc><aside class="el-aside menu" style="width:auto;" data-v-67e96130 data-v-80d5f2bc><ul role="menubar" class="menu-wrap el-menu" style="background-color:;" data-v-67e96130><li data-v-67e96130><div class="brand-wrap" style="background-image:url(/brand.jpg);" data-v-67e96130><div class="brand" data-v-67e96130><a href="/" class="avatar waves-effect waves-circle waves-light router-link-active" data-v-67e96130><img src="/avatar.jpg" data-v-67e96130></a> <hgroup class="introduce" data-v-67e96130><div class="nickname" data-v-67e96130>zzqhost</div> <a title="zzqhost@163.com" class="mail" data-v-67e96130>zzqhost@163.com</a></hgroup></div></div></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-home" data-v-67e96130></i> <span class="item-title" data-v-67e96130>主页</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-biaoqian" data-v-67e96130></i> <span class="item-title" data-v-67e96130>标签分类</span></li> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-wenzhang" data-v-67e96130></i> <span class="item-title" data-v-67e96130>时间归档</span></li> <!----> <li role="menuitem" tabindex="-1" class="el-menu-item" style="padding-left:20px;color:;background-color:;" data-v-67e96130><i class="iconfont icon-aboutme" data-v-67e96130></i> <span class="item-title" data-v-67e96130>自我介绍</span></li></ul></aside> <section class="el-container container-warp" data-v-80d5f2bc><header id="topHeader" class="el-header top-header" style="height:60px;padding-left:260px;" data-v-1a942948 data-v-80d5f2bc><div class="header-warp el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-12 el-col-xs-7" data-v-1a942948><div class="el-row is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-2" data-v-1a942948><button type="button" class="el-button el-button--primary is-circle" data-v-1a942948><!----><!----><span><i class="iconfont icon-caidan" data-v-1a942948></i></span></button></div></div></div> <div class="el-col el-col-20 el-col-xs-24" data-v-1a942948><div class="grid-content bg-purple-light" data-v-1a942948><div class="el-row is-justify-end is-align-middle el-row--flex" data-v-1a942948><div class="el-col el-col-13 el-col-xs-24 el-col-sm-21 el-col-md-17 el-col-lg-13" data-v-1a942948><div aria-haspopup="listbox" role="combobox" aria-owns="el-autocomplete-8527" class="el-autocomplete search-input" data-v-1a942948><div class="el-input el-input--small el-input--suffix"><!----><input type="text" autocomplete="off" valueKey="value" popperClass="search-popper" placeholder="搜搜看" fetchSuggestions="function () { [native code] }" debounce="300" placement="bottom-start" popperAppendToBody="true" value="" class="el-input__inner"><!----><span class="el-input__suffix"><span class="el-input__suffix-inner"><i class="el-input__icon el-icon-search search-ico" data-v-1a942948></i><!----></span><!----></span><!----></div><div role="region" class="el-autocomplete-suggestion el-popper search-popper" style="width:;display:none;"><div class="el-scrollbar"><div class="el-autocomplete-suggestion__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default"><ul class="el-scrollbar__view el-autocomplete-suggestion__list"></ul></div><div class="el-scrollbar__bar is-horizontal"><div class="el-scrollbar__thumb" style="width:0;transform:translateX(0%);ms-transform:translateX(0%);webkit-transform:translateX(0%);"></div></div><div class="el-scrollbar__bar is-vertical"><div class="el-scrollbar__thumb" style="height:0;transform:translateY(0%);ms-transform:translateY(0%);webkit-transform:translateY(0%);"></div></div></div></div></div></div></div></div></div></div></header> <main class="el-main my-main" style="margin-left:240px;" data-v-105de776 data-v-80d5f2bc><div class="content-header index-header" data-v-60d87e45 data-v-105de776><div class="container fade-scale in" data-v-60d87e45><h1 id="conentHeader" class="title" data-v-60d87e45>Android中JSBridge的原理与实现</h1> <h5 class="subtitle" data-v-60d87e45>最后更新时间：2019-07-04 18:08:36</h5></div></div> <div data-v-95d4b5b2 data-v-105de776><div class="post-content el-row is-justify-center el-row--flex" data-v-95d4b5b2><div id="post-card" class="post-card post-sign el-col el-col-16 el-col-xs-24 el-col-sm-23 el-col-md-23 el-col-lg-16" data-v-95d4b5b2><div class="content__default" data-v-95d4b5b2><p>首先我们来了解一下什么是JSBridge和为什么要使用JSBridge？</p> <p>在开发中，为了追求开发的效率以及移植的便利性，一些展示性强的页面我们会偏向于使用h5来完成，功能性强的页面我们会偏向于使用native来完成，而一旦使用了h5，为了在h5中尽可能的得到native的体验，我们native层需要暴露一些方法给js调用，比如，弹Toast提醒，弹Dialog，分享等等，有时候甚至把h5的网络请求放到native去完成。</p> <p>JSBridge做得好的一个典型就是微信，微信给开发者提供了JSSDK，该SDK中暴露了很多微信native层的方法，比如支付，定位等。</p> <p>本文将对js和Native的通信原理和实现方法的一些探讨。
</p> <h2 id="实现jsbridge关键点的原理剖析"><a href="#实现jsbridge关键点的原理剖析" aria-hidden="true" class="header-anchor">#</a> 实现JSBridge关键点的原理剖析</h2> <p>Android中的JSBridge是H5与Native通信的桥梁，其作用是实现H5与Native间的双向通信。要实现H5与Native的双向通信，解决如下四个问题即可：</p> <ol><li>Java如何调用JavaScript</li> <li>JavaScript如何调用Java</li> <li>方法参数以及回调如何处理</li> <li>通信协议的制定</li></ol> <p>下面从以上问题依次开始讨论</p> <h3 id="java如何调用javascript"><a href="#java如何调用javascript" aria-hidden="true" class="header-anchor">#</a> Java如何调用JavaScript</h3> <p>在WebView中，如果java要调用js的方法，是非常容易做到的，使用WebView.loadUrl(“javascript:function()”)即可，这样，就做到了JSBridge的native层调用h5层的单向通信</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code>    <span class="token class-name">WebView</span><span class="token punctuation">.</span><span class="token function">loadUrl</span><span class="token punctuation">(</span><span class="token string">&quot;javascript:function()&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h3 id="javascript如何调用java"><a href="#javascript如何调用java" aria-hidden="true" class="header-anchor">#</a> JavaScript如何调用Java</h3> <p>js调用Android的方法有以下四种：</p> <ol><li>WebView 的 JavascriptInterface</li> <li>WebViewClient.shouldOverrideUrlLoading()</li> <li>WebChromeClient.onConsoleMessage()</li> <li>WebChromeClient.onJsPrompt()、onJsAlert()、onJsConfirm()
我们先对此四种方案进行一个详细的描述，最后选择一个方案即可。本文章中采用了第四种方案。</li></ol> <h4 id="javascriptinterface"><a href="#javascriptinterface" aria-hidden="true" class="header-anchor">#</a> JavascriptInterface</h4> <p>JavascriptInterface是Android官方提供的js和Native通信方案。其实现如下：</p> <ol><li>实现一个java类，供js调用</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MyJavascriptInterface</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@JavascriptInterface</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">showToast</span><span class="token punctuation">(</span><span class="token class-name">String</span> toast<span class="token punctuation">)</span> <span class="token punctuation">{</span>             
       <span class="token class-name">Toast</span><span class="token punctuation">.</span><span class="token function">makeText</span><span class="token punctuation">(</span><span class="token class-name">MainActivity</span><span class="token punctuation">.</span><span class="token keyword">this</span><span class="token punctuation">,</span> toast<span class="token punctuation">,</span> <span class="token class-name">Toast</span><span class="token punctuation">.</span>LENGTH_SHORT<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><ol start="2"><li>在webView中注册这个类：</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code>webView<span class="token punctuation">.</span><span class="token function">addJavascriptInterface</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MyJavascriptInterface</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">&quot;javascriptInterface&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><ol start="3"><li>在js中直接调用这个接口：</li></ol> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code><span class="token keyword">function</span> <span class="token function">showToast</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    window<span class="token punctuation">.</span>javascriptInterface<span class="token punctuation">.</span><span class="token function">showToast</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><ol start="4"><li>总结
大多数人都知道WebView存在一个漏洞，见<a href="http://blog.csdn.net/jackrex/article/details/11110675" target="_blank" rel="noopener noreferrer">WebView中接口隐患与手机挂马利用<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a>，虽然该漏洞已经在Android 4.2上修复了（即使用@JavascriptInterface代替addJavascriptInterface），但是由于兼容性和安全性问题，基本上我们不会再利用Android系统为我们提供的addJavascriptInterface方法或者@JavascriptInterface注解来实现，所以我们只能另辟蹊径，去寻找既安全，又能实现兼容Android各个版本的方案。</li></ol> <h4 id="webviewclient-shouldoverrideurlloading"><a href="#webviewclient-shouldoverrideurlloading" aria-hidden="true" class="header-anchor">#</a> WebViewClient.shouldOverrideUrlLoading()</h4> <p>这个方法是拦截所有webView的跳转，页面可以构造一个特殊格式的Url跳转，shouldOverrideUrlLoading拦截Url后判断其格式，然后Native就能执行自身的逻辑了。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomWebViewClient</span> <span class="token keyword">extends</span> <span class="token class-name">WebViewClient</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">shouldOverrideUrlLoading</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> view<span class="token punctuation">,</span> <span class="token class-name">String</span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isJsBridgeUrl</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// JSbridge的处理逻辑</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">shouldOverrideUrlLoading</span><span class="token punctuation">(</span>view<span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h4 id="webchromeclient-onconsolemessage"><a href="#webchromeclient-onconsolemessage" aria-hidden="true" class="header-anchor">#</a> WebChromeClient.onConsoleMessage()</h4> <p>在js中执行console.log(), 会进入Android的WebChromeClient.consoleMessage()回调。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code>  <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomWebChromeClient</span> <span class="token keyword">extends</span> <span class="token class-name">WebChromeClient</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">onConsoleMessage</span><span class="token punctuation">(</span><span class="token class-name">ConsoleMessage</span> consoleMessage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onConsoleMessage</span><span class="token punctuation">(</span>consoleMessage<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token class-name">String</span> msg <span class="token operator">=</span> consoleMessage<span class="token punctuation">.</span><span class="token function">message</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//Javascript输入的Log内容</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="webchromeclient-onjsprompt"><a href="#webchromeclient-onjsprompt" aria-hidden="true" class="header-anchor">#</a> WebChromeClient.onJsPrompt()</h4> <ol><li>在WebView有一个方法，叫setWebChromeClient，可以设置WebChromeClient对象，而这个对象中有三个方法，分别是onJsAlert,onJsConfirm,onJsPrompt，当js调用window对象的对应的方法，即window.alert，window.confirm，window.prompt，WebChromeClient对象中的三个方法对应的就会被触发，那这三个方法到底要使用哪个呢？</li> <li>这三个方法的区别，可以详见w3c <a href="http://www.w3school.com.cn/js/js_popup.asp" target="_blank" rel="noopener noreferrer">JavaScript 消息框<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a> 。</li> <li>一般来说，我们是不会使用onJsAlert的，为什么呢？因为js中alert使用的频率还是非常高的，一旦我们占用了这个通道，alert的正常使用就会受到影响，而confirm和prompt的使用频率相对alert来说，则更低一点。</li> <li>那么到底是选择confirm还是prompt呢，其实confirm的使用频率也是不低的，比如你点一个链接下载一个文件，这时候如果需要弹出一个提示进行确认，点击确认就会下载，点取消便不会下载，类似这种场景还是很多的，因此不能占用confirm。</li> <li>而prompt则不一样，在Android中，几乎不会使用到这个方法，就是用，也会进行自定义，所以我们完全可以使用这个方法。该方法就是弹出一个输入框，然后让你输入，输入完成后返回输入框中的内容。因此，占用prompt是再完美不过了。</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code>  <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CustomWebChromeClient</span> <span class="token keyword">extends</span> <span class="token class-name">WebChromeClient</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">onJsPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">onJsPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  myWebView<span class="token punctuation">.</span><span class="token function">setWebChromClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CustomWebChromeClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h3 id="方法参数以及回调处理"><a href="#方法参数以及回调处理" aria-hidden="true" class="header-anchor">#</a> 方法参数以及回调处理</h3> <ol><li>任何IPC通信都涉及到参数序列化的问题，同理，Java与JavaScript之间只能传递基础类型（包括基本类型和字符串），不包括其他对象或者函数。所以可以采用json格式来传递数据。</li> <li>为了实现异步返回结果，所以JavaScript与Java相互调用不能直接获取返回值，只能通过回调的方式来获取返回结果。</li></ol> <h3 id="通信协议的制定"><a href="#通信协议的制定" aria-hidden="true" class="header-anchor">#</a> 通信协议的制定</h3> <p>要进行正常的通信，通信协议的制定是必不可少的。我们回想一下熟悉的http请求url的组成部分。形如http://host:port/path?param=value, 我们参考http，制定JSBridge的组成部分</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>  jsbridge://className:callbackAddress/methodName?jsonObj

  // className: 表示java的类名
  // callbackAddress： js回调的标识
  // methodName： java中的方法名
  // jsonObj： 接口数据
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h2 id="具体实践"><a href="#具体实践" aria-hidden="true" class="header-anchor">#</a> 具体实践</h2> <h3 id="调用流程"><a href="#调用流程" aria-hidden="true" class="header-anchor">#</a> 调用流程</h3> <ol><li>在js中，可以采用如下方法调用java方法</li></ol> <div class="language-javascript line-numbers-mode"><pre class="language-javascript"><code>  <span class="token keyword">var</span> JSBridge <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token function-variable function">call</span><span class="token punctuation">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">className<span class="token punctuation">,</span> method<span class="token punctuation">,</span> params<span class="token punctuation">,</span> callback</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">var</span> uri <span class="token operator">=</span> <span class="token string">'jsbridge://'</span> <span class="token operator">+</span> className <span class="token operator">+</span> <span class="token string">':'</span> <span class="token operator">+</span> callback <span class="token operator">+</span> <span class="token string">'/'</span> <span class="token operator">+</span> method <span class="token operator">+</span> <span class="token string">'?'</span> <span class="token operator">+</span> params<span class="token punctuation">;</span>
      window<span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span>uri<span class="token punctuation">,</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 下面会调用java中的 bridge.showToast方法</span>
  <span class="token function">JSBridge</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token string">'bridge'</span><span class="token punctuation">,</span> <span class="token string">'showToast'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token string">'msg'</span><span class="token punctuation">:</span><span class="token string">'Hello JSBridge'</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token function">alert</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><ol start="2"><li>在java中， 可以如下实现：</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 进入prompt回调</span>
  <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JSBridgeWebChromeClient</span> <span class="token keyword">extends</span> <span class="token class-name">WebChromeClient</span> <span class="token punctuation">{</span>      
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">onJsPrompt</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> view<span class="token punctuation">,</span> <span class="token class-name">String</span> url<span class="token punctuation">,</span> <span class="token class-name">String</span> message<span class="token punctuation">,</span> <span class="token class-name">String</span> defaultValue<span class="token punctuation">,</span> <span class="token class-name">JsPromptResult</span> result<span class="token punctuation">)</span> <span class="token punctuation">{</span>            
      result<span class="token punctuation">.</span><span class="token function">confirm</span><span class="token punctuation">(</span><span class="token class-name">JSBridge</span><span class="token punctuation">.</span><span class="token function">callJava</span><span class="token punctuation">(</span>view<span class="token punctuation">,</span> message<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 调用java逻辑</span>
  <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JSBridge</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">callJava</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> webView<span class="token punctuation">,</span> <span class="token class-name">String</span> uriString<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> methodName <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> className <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> param <span class="token operator">=</span> <span class="token string">&quot;{}&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> port <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">TextUtils</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>uriString<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> uriString<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">&quot;JSBridge&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Uri</span> uri <span class="token operator">=</span> <span class="token class-name">Uri</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>uriString<span class="token punctuation">)</span><span class="token punctuation">;</span>
            className <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            param <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getQuery</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            port <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getPort</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
            <span class="token class-name">String</span> path <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">TextUtils</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                methodName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// 基于上面的className、methodName和port path调用对应类的方法</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>exposedMethods<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Method</span><span class="token punctuation">&gt;</span></span> methodHashMap <span class="token operator">=</span> exposedMethods<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>methodHashMap <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> methodHashMap<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> methodHashMap<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>methodName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Method</span> method <span class="token operator">=</span> methodHashMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>methodName<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>method <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">try</span> <span class="token punctuation">{</span>
                        method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> webView<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span>param<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Callback</span><span class="token punctuation">(</span>webView<span class="token punctuation">,</span> port<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

  <span class="token comment">// 直接进入showToast函数的实现</span>
  <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">showToast</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> webView<span class="token punctuation">,</span> <span class="token class-name">JSONObject</span> param<span class="token punctuation">,</span> <span class="token keyword">final</span> <span class="token class-name">Callback</span> callback<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">String</span> message <span class="token operator">=</span> param<span class="token punctuation">.</span><span class="token function">optString</span><span class="token punctuation">(</span><span class="token string">&quot;msg&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Toast</span><span class="token punctuation">.</span><span class="token function">makeText</span><span class="token punctuation">(</span>webView<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> message<span class="token punctuation">,</span> <span class="token class-name">Toast</span><span class="token punctuation">.</span>LENGTH_SHORT<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">null</span> <span class="token operator">!=</span> callback<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">JSONObject</span> object <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            object<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;key&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;value&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            object<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">&quot;key1&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;value1&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            callback<span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token function">getJSONObject</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">&quot;ok&quot;</span><span class="token punctuation">,</span> object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
     <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 上述程序的callback.apply方法实现如下： 即通过webView.loadUrl实现java调用js的方法</span>
  <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Callback</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Handler</span> mHandler <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Handler</span><span class="token punctuation">(</span><span class="token class-name">Looper</span><span class="token punctuation">.</span><span class="token function">getMainLooper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> CALLBACK_JS_FORMAT <span class="token operator">=</span> <span class="token string">&quot;javascript:JSBridge.onFinish('%s', %s);&quot;</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> mPort<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">WeakReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">WebView</span><span class="token punctuation">&gt;</span></span> mWebViewRef<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">Callback</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> view<span class="token punctuation">,</span> <span class="token class-name">String</span> port<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        mWebViewRef <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeakReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>view<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mPort <span class="token operator">=</span> port<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">apply</span><span class="token punctuation">(</span><span class="token class-name">JSONObject</span> jsonObject<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token class-name">String</span> execJs <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>CALLBACK_JS_FORMAT<span class="token punctuation">,</span> mPort<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>jsonObject<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mWebViewRef <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> mWebViewRef<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            mHandler<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token annotation punctuation">@Override</span>
                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    mWebViewRef<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">loadUrl</span><span class="token punctuation">(</span>execJs<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token punctuation">}</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br><span class="line-number">81</span><br><span class="line-number">82</span><br><span class="line-number">83</span><br><span class="line-number">84</span><br><span class="line-number">85</span><br><span class="line-number">86</span><br><span class="line-number">87</span><br><span class="line-number">88</span><br><span class="line-number">89</span><br></div></div><h3 id="安全性及其它"><a href="#安全性及其它" aria-hidden="true" class="header-anchor">#</a> 安全性及其它</h3> <ol><li>JSBridge类管理暴露给前端方法，前端调用的方法应该在此类中注册才可使用。register的实现是从Map中查找key是否存在，不存在则反射取得对应class中的所有方法,具体方法是在BridgeImpl中定义的，方法包括三个参数分别为WebView、JSONObject、CallBack。如果满足条件，则将所有满足条件的方法put到map中。</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">HashMap</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Method</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> exposedMethods <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">String</span> exposedName<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span> <span class="token keyword">extends</span> <span class="token class-name">IBridge</span><span class="token punctuation">&gt;</span></span> clazz<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>exposedMethods<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>exposedName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">try</span> <span class="token punctuation">{</span>
                exposedMethods<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>exposedName<span class="token punctuation">,</span> <span class="token function">getAllMethod</span><span class="token punctuation">(</span>clazz<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><ol start="2"><li>JSBridge类中的callJava方法就是将js传递过来的URL解析，根据将要调用的类名从刚刚建立的Map中找出，根据方法名调用具体的方法，并将解析出的三个参数传递进去。</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">callJava</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> webView<span class="token punctuation">,</span> <span class="token class-name">String</span> uriString<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> methodName <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> className <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> param <span class="token operator">=</span> <span class="token string">&quot;{}&quot;</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> port <span class="token operator">=</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">TextUtils</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>uriString<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> uriString<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">&quot;JSBridge&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">Uri</span> uri <span class="token operator">=</span> <span class="token class-name">Uri</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>uriString<span class="token punctuation">)</span><span class="token punctuation">;</span>
            className <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            param <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getQuery</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            port <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getPort</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
            <span class="token class-name">String</span> path <span class="token operator">=</span> uri<span class="token punctuation">.</span><span class="token function">getPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token class-name">TextUtils</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                methodName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>


        <span class="token keyword">if</span> <span class="token punctuation">(</span>exposedMethods<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Method</span><span class="token punctuation">&gt;</span></span> methodHashMap <span class="token operator">=</span> exposedMethods<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span>methodHashMap <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> methodHashMap<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> methodHashMap<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>methodName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">Method</span> method <span class="token operator">=</span> methodHashMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>methodName<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>method <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token keyword">try</span> <span class="token punctuation">{</span>
                        method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> webView<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span>param<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Callback</span><span class="token punctuation">(</span>webView<span class="token punctuation">,</span> port<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br></div></div><ol start="3"><li>CallBack类是用来回调js中回调方法的Java对应类。Java层处理好的返回结果是通过CallBack类来实现的。在这个回调类中传递的参数是JSONObject（返回结果）、WebView和port，port应与js传递过来的port相对应。</li></ol> <div class="language-Java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Handler</span> mHandler <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Handler</span><span class="token punctuation">(</span><span class="token class-name">Looper</span><span class="token punctuation">.</span><span class="token function">getMainLooper</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> CALLBACK_JS_FORMAT <span class="token operator">=</span> <span class="token string">&quot;javascript:JSBridge.onFinish('%s', %s);&quot;</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> mPort<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">WeakReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">WebView</span><span class="token punctuation">&gt;</span></span> mWebViewRef<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">Callback</span><span class="token punctuation">(</span><span class="token class-name">WebView</span> view<span class="token punctuation">,</span> <span class="token class-name">String</span> port<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        mWebViewRef <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WeakReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>view<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mPort <span class="token operator">=</span> port<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">apply</span><span class="token punctuation">(</span><span class="token class-name">JSONObject</span> jsonObject<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token class-name">String</span> execJs <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>CALLBACK_JS_FORMAT<span class="token punctuation">,</span> mPort<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>jsonObject<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mWebViewRef <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> mWebViewRef<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            mHandler<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token annotation punctuation">@Override</span>
                <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    mWebViewRef<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">loadUrl</span><span class="token punctuation">(</span>execJs<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><ol start="4"><li>在java层的JSBridge中注册方法，例如</li></ol> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">JSBridge</span><span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token string">&quot;bridge&quot;</span><span class="token punctuation">,</span> <span class="token class-name">BridgeImpl</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h2 id="参考文献"><a href="#参考文献" aria-hidden="true" class="header-anchor">#</a> 参考文献</h2> <ul><li><a href="http://blog.csdn.net/starsliu/article/details/50820453" target="_blank" rel="noopener noreferrer">Android JSBridge的原理与实现<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li> <li><a href="https://www.jianshu.com/p/2ec3f06d6087" target="_blank" rel="noopener noreferrer">Android中JSBridge的原理与实现<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li> <li><a href="https://www.jianshu.com/p/7ee7ab68c095" target="_blank" rel="noopener noreferrer">Android JsBridge<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></li></ul></div> <span id="footerPost" data-v-95d4b5b2></span></div> <div id="post-toc" class="post-toc el-col el-col-6" data-v-95d4b5b2><h4 class="catalog-title" data-v-95d4b5b2>TOC</h4> <div class="catalog-body" data-v-95d4b5b2><ul id="catalog-list" class="catalog-list" data-v-95d4b5b2></ul></div></div></div> <div class="post-nav el-row is-justify-space-around el-row--flex" data-v-95d4b5b2><div class="post-prev el-col el-col-7" data-v-95d4b5b2><div data-v-95d4b5b2><a href="/posts/hexo%E7%9A%84%E6%BA%90%E7%A0%81%E4%BB%93%E5%BA%93.html" data-v-95d4b5b2><i class="el-icon-arrow-left" data-v-95d4b5b2></i> Prev
        </a> <p class="nav-title" data-v-95d4b5b2>hexo的源码仓库</p></div></div> <div class="post-next el-col el-col-7 el-col-lg-pull-5" data-v-95d4b5b2><div data-v-95d4b5b2><a href="/posts/%E6%84%9F%E5%86%92%E7%9A%84%E5%88%86%E7%B1%BB%E5%8F%8A%E6%B2%BB%E7%96%97.html" data-v-95d4b5b2>
          Next
          <i class="el-icon-arrow-right" data-v-95d4b5b2></i></a> <p class="nav-title" data-v-95d4b5b2>感冒的分类及治疗</p></div></div></div> <div class="el-row is-justify-center el-row--flex" data-v-95d4b5b2></div> <span data-v-d999c3f2 data-v-95d4b5b2><button type="button" class="el-button toc-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="iconfont icon-service-directory" data-v-d999c3f2></i></span></button> <button type="button" class="el-button gotop-btn el-button--primary is-circle" data-v-d999c3f2><!----><!----><span><i class="el-icon-arrow-up" data-v-d999c3f2></i></span></button></span></div></main></section> <button type="button" class="el-button gotop-btn el-button--primary is-circle" style="display:none;" data-v-78a2dcfa data-v-80d5f2bc><!----><!----><span><i class="el-icon-arrow-up" data-v-78a2dcfa></i></span></button></section> <footer class="el-footer container-footer" style="height:60px;" data-v-76c50ee3 data-v-80d5f2bc><div class="footer-warp el-row is-justify-center is-align-center el-row--flex footerMargin" data-v-76c50ee3><div class="footer-top el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3>
          博客内容遵循
          <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" data-v-76c50ee3>知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span></p></div> <div class="footer-bottom el-col el-col-24" data-v-76c50ee3><p class="ellipsis" data-v-76c50ee3><span data-v-76c50ee3><span data-v-76c50ee3>
            张志强的博客 © 2017-01 ~ 2021-03
          </span></span> <span data-v-76c50ee3>
          Power by
          <a href="https://vuepress.vuejs.org/zh/" target="_blank" data-v-76c50ee3>VuePress</a> Theme
          <a href="https://github.com/zhhlwd/vuepress-theme-indigo-material" target="_blank" data-v-76c50ee3>indigo material</a></span></p></div></div></footer> <div class="overlay" data-v-80d5f2bc></div></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.3e01f5cb.js" defer></script><script src="/assets/js/1.21aaee9f.js" defer></script><script src="/assets/js/14.98a4de9c.js" defer></script><script src="/assets/js/5.352c1a43.js" defer></script><script src="/assets/js/7.4a8a313c.js" defer></script><script src="/assets/js/9.5ce2172b.js" defer></script><script src="/assets/js/6.8b8fad13.js" defer></script><script src="/assets/js/20.95040517.js" defer></script><script src="/assets/js/13.186562af.js" defer></script><script src="/assets/js/15.740f4afc.js" defer></script>
  </body>
</html>
